home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include "global.h"
- #include "mbuf.h"
- #include "socket.h"
- #include "telnet.h"
- #include "session.h"
- #include "proc.h"
- #include "tty.h"
- #include "commands.h"
- #include "netuser.h"
-
- #define CTLZ 26
-
- extern char Nospace[];
- extern char Badhost[];
-
- static void doopt __ARGS((struct telnet *tn,char opt));
- static void dontopt __ARGS((struct telnet *tn,char opt));
- static void willopt __ARGS((struct telnet *tn,char opt));
- static void wontopt __ARGS((struct telnet *tn,char opt));
- static void answer __ARGS((struct telnet *tn,int r1,int r2));
-
- int Refuse_echo = 0;
- int Unix_line_mode = 0; /* if true turn <cr> to <nl> when in line mode */
-
- #ifdef DEBUG
- char *T_options[] = {
- "Transmit Binary",
- "Echo",
- "",
- "Suppress Go Ahead",
- "",
- "Status",
- "Timing Mark"
- };
- #endif
-
- /* Execute user telnet command */
- int
- dotelnet(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct session *sp;
- struct telnet tn;
- struct sockaddr_in fsocket;
- struct mbuf *bp;
- char *cp;
-
- /* Allocate a session descriptor */
- if((sp = newsession(argv[1],TELNET)) == NULLSESSION){
- printf("Too many sessions\n");
- freeargs(argc,argv);
- return 1;
- }
- /* Initialize Telnet protocol descriptor */
- memset((char *)&tn,0,sizeof(tn));
- tn.output = Curproc;
- tn.session = sp; /* Upward pointer */
- sp->cb.telnet = &tn; /* Downward pointer */
-
- fsocket.sin_family = AF_INET;
- if(argc < 3)
- fsocket.sin_port = IPPORT_TELNET;
- else
- fsocket.sin_port = atoi(argv[2]);
-
- freeargs(argc,argv);
- Current = sp;
- Mode = CONV_MODE;
- if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
- printf(Badhost,sp->name);
- freesession(sp);
- return 1;
- }
- if((sp->s = socket(AF_INET,SOCK_STREAM,0)) == -1){
- printf("Can't create socket\n");
- freesession(sp);
- return 1;
- }
- printf("Trying %s...\n",psocket((struct sockaddr *)&fsocket));
- if(connect(sp->s,(char *)&fsocket,SOCKSIZE) == -1){
- cp = sockerr(sp->s);
- printf("Telnet session %u connect failed: %s\n",
- (unsigned)(sp-Sessions),cp != NULLCHAR ? cp : "");
- freesession(sp);
- return 1;
- }
- printf("Telnet session %u connected to %s\n",
- (unsigned)(sp-Sessions),sp->name);
- /* Fork off the receiver process */
- tn.input = newproc("tel_in",512,tel_input,0,&tn,NULL);
-
- /* Now send whatever's typed on the terminal */
- for(;;){
- while(sp->input == NULLBUF)
- if(pwait(&sp->input) == -1)
- goto quit;
-
- bp = dequeue(&sp->input);
-
- /* If we're doing our own echoing and recording is enabled,
- * record it
- */
- if(!tn.remote[TN_ECHO] && sp->record != NULLFILE)
- write_p(sp->record,bp);
- if(send_mbuf(sp->s,bp,0,NULLCHAR,0) == -1)
- break;
- }
- quit: close_s(sp->s);
- killproc(tn.input);
- freesession(sp);
- return 0;
- }
-
- /* User telnet receive task, started by user telnet command */
- void
- tel_input(unused,tn1,p)
- int unused;
- void *tn1;
- void *p;
- {
- int c;
- FILE *record;
- struct session *sp;
- char *cp;
- struct mbuf *bp = NULLBUF;
- struct telnet *tn;
-
- tn = (struct telnet *)tn1;
- sp = tn->session;
-
- while((c = recvchar(sp->s,&bp)) != -1){
-
- /* Suspend output if we're not current */
- while(Current != sp || Mode != CONV_MODE)
- if(pwait(sp) == -1)
- goto quit;
-
- if(uchar(c) == IAC){
- /* IAC received, get command sequence */
- c = recvchar(sp->s,&bp);
- switch(uchar(c)){
- case WILL:
- willopt(tn,recvchar(sp->s,&bp));
- break;
- case WONT:
- wontopt(tn,recvchar(sp->s,&bp));
- break;
- case DO:
- doopt(tn,recvchar(sp->s,&bp));
- break;
- case DONT:
- dontopt(tn,recvchar(sp->s,&bp));
- break;
- case IAC: /* Escaped IAC */
- putchar(IAC);
- if((record = sp->record) != NULLFILE)
- putc(IAC,record);
- break;
- }
- } else {
- /* Ordinary character */
- if(!tn->remote[TN_TRANSMIT_BINARY])
- c &= 0x7f;
-
- putchar(c);
- if((record = sp->record) != NULLFILE)
- putc(c,record);
- }
- }
- quit: /* Close seen from remote host */
- free_p(bp);
- cp = sockerr(sp->s);
- printf("Telnet session %u closed: %s\n", (unsigned)(sp - Sessions),
- cp != NULLCHAR ? cp : "EOF");
- close_s(sp->s);
- killproc(tn->output);
- freesession(sp);
- }
-
- /* File uploading task */
- void
- tel_upload(unused,sp1,p)
- int unused;
- void *sp1;
- void *p;
- {
- struct telnet *tn;
- struct session *sp;
- struct mbuf *bp;
- int c;
- char *cp;
-
- sp = (struct session *)sp1;
- tn = sp->cb.telnet;
-
- /* Initialize current output buffer */
- bp = alloc_mbuf(BUFSIZ);
- cp = bp->data;
-
- while((c = getc(sp->upload)) != EOF){
- if(bp->cnt >= BUFSIZ-2){
- /* If buffer can't take two more characters, flush
- * it and get a new one. This allows for a cr/lf
- * at the end of the buffer.
- */
- send_mbuf(sp->s,bp,0,NULLCHAR,0);
- bp = alloc_mbuf(BUFSIZ);
- cp = bp->data;
- }
- /* Copy to output, translating newlines to CR/LF */
- if(c == '\n'){
- *cp++ = '\r';
- bp->cnt++;
- }
- *cp++ = c;
- bp->cnt++;
- }
- /* Send last buffer, if not empty */
- if(bp->cnt != 0)
- send_mbuf(sp->s,bp,0,NULLCHAR,0);
- else
- free_p(bp);
-
- fclose(sp->upload);
- sp->upload = NULLFILE;
- free(sp->ufile);
- sp->ufile = NULLCHAR;
- tn->upload = NULLPROC;
- }
- /* The guts of the actual Telnet protocol: negotiating options */
- static
- void
- willopt(tn,opt)
- struct telnet *tn;
- char opt;
- {
- int ack;
-
- #ifdef DEBUG
- printf("recv: will ");
- if(uchar(opt) <= NOPTIONS)
- printf("%s\n",T_options[opt]);
- else
- printf("%u\n",opt);
- #endif
-
- switch(uchar(opt)){
- case TN_TRANSMIT_BINARY:
- case TN_ECHO:
- case TN_SUPPRESS_GA:
- if(tn->remote[uchar(opt)] == 1)
- return; /* Already set, ignore to prevent loop */
- if(uchar(opt) == TN_ECHO){
- if(Refuse_echo){
- /* User doesn't want to accept */
- ack = DONT;
- break;
- } else
- ttysetmode(0); /* Put tty into raw mode */
- }
- tn->remote[uchar(opt)] = 1;
- ack = DO;
- break;
- default:
- ack = DONT; /* We don't know what he's offering; refuse */
- }
- answer(tn,ack,opt);
- }
- static void
- wontopt(tn,opt)
- struct telnet *tn;
- char opt;
- {
- #ifdef DEBUG
- printf("recv: wont ");
- if(uchar(opt) <= NOPTIONS)
- printf("%s\n",T_options[uchar(opt)]);
- else
- printf("%u\n",uchar(opt));
- #endif
- if(uchar(opt) <= NOPTIONS){
- if(tn->remote[uchar(opt)] == 0)
- return; /* Already clear, ignore to prevent loop */
- tn->remote[uchar(opt)] = 0;
- if(uchar(opt) == TN_ECHO)
- ttysetmode(TTY_ECHO|TTY_EDIT); /* Put tty into cooked mode */
- }
- answer(tn,DONT,opt); /* Must always accept */
- }
- static void
- doopt(tn,opt)
- struct telnet *tn;
- char opt;
- {
- int ack;
-
- #ifdef DEBUG
- printf("recv: do ");
- if(uchar(opt) <= NOPTIONS)
- printf("%s\n",T_options[uchar(opt)]);
- else
- printf("%u\n",uchar(opt));
- #endif
- switch(uchar(opt)){
- #ifdef FUTURE /* Use when local options are implemented */
- if(tn->local[uchar(opt)] == 1)
- return; /* Already set, ignore to prevent loop */
- tn->local[uchar(opt)] = 1;
- ack = WILL;
- break;
- #endif
- default:
- ack = WONT; /* Don't know what it is */
- }
- answer(tn,ack,opt);
- }
- static void
- dontopt(tn,opt)
- struct telnet *tn;
- char opt;
- {
- #ifdef DEBUG
- printf("recv: dont ");
- if(uchar(opt) <= NOPTIONS)
- printf("%s\n",T_options[uchar(opt)]);
- else
- printf("%u\n",uchar(opt));
- #endif
- if(uchar(opt) <= NOPTIONS){
- if(tn->local[uchar(opt)] == 0){
- /* Already clear, ignore to prevent loop */
- return;
- }
- tn->local[uchar(opt)] = 0;
- }
- answer(tn,WONT,opt);
- }
- static void
- answer(tn,r1,r2)
- struct telnet *tn;
- int r1,r2;
- {
- char s[3];
-
- #ifdef DEBUG
- switch(r1){
- case WILL:
- printf("sent: will ");
- break;
- case WONT:
- printf("sent: wont ");
- break;
- case DO:
- printf("sent: do ");
- break;
- case DONT:
- printf("sent: dont ");
- break;
- }
- if(r2 <= 6)
- printf("%s\n",T_options[r2]);
- else
- printf("%u\n",r2);
- #endif
-
- s[0] = IAC;
- s[1] = r1;
- s[2] = r2;
- send(tn->session->s,s,3,0);
- }
-